const NoLanes = /*                        */ 0b0000000000000000000000000000000;
const NoLane = /*                         */ 0b0000000000000000000000000000000;
const SyncLane = /*                       */ 0b0000000000000000000000000000001; // 1
const DefaultLane = /*                    */ 0b0000000000000000000000000010000; // 16

function isSubsetOfLanes(set, subset) {
  return (set & subset) === subset;
}

function mergeLanes(a, b) {
  return a | b;
}

function initializeUpdateQueue(fiber) {
  const queue = {
    baseState: fiber.memoizedState,
    firstBaseUpdate: null,
    lastBaseUpdate: null,
    shared: {
      pending: null,
    },
  };
  fiber.updateQueue = queue;
}

const UpdateState = 0;

function createUpdate(lane) {
  const update = {
    tag: UpdateState,
    lane,
    payload: null,
    next: null,
  };
  return update;
}

function enqueueUpdate(fiber, update) {
  const updateQueue = fiber.updateQueue;

  if (updateQueue === null) {
    return;
  }
  const sharedQueue = updateQueue.shared;
  const pending = sharedQueue.pending;
  if (pending === null) {
    // 第一个更新
    update.next = update;
  } else {
    update.next = pending.next;
    pending.next = update;
  }
  sharedQueue.pending = update;
}

function getStateFromUpdate(update, prevState, nextProps, instance) {
  switch (update.tag) {
    case UpdateState: {
      const payload = update.payload;
      let partialState;

      if (typeof payload === 'function') {
        //
        partialState = payload.call(instance, prevState, nextProps);
      } else {
        partialState = payload;
      }

      if (partialState === null || partialState === undefined) {
        return prevState;
      }
      return Object.assign({}, prevState, partialState);
    }
  }

  return prevState;
}

/**
 * 处理 workInProgress.updateQueue 主要包括以下几个方面
 * 1. 将 updateQueue.shared.pending 的环状链表解开环，使用 firstBaseUpdate 跟 lastBaseUpdate 分别指向更新链表的头跟尾
 * 2. 找出满足渲染优先级的所有更新，计算出这此更新最终的状态 newState
 * 3. 如果有不满足渲染优先级的更新，更新链表会记录 workInProgress 中所有更新（跳过的跟没有跳过的），并用 updateQueue.firstBaseUpdate 跟 updateQueue.lastUpdate 分别指向更新链表的头跟尾
 * 4. 将满足条件更新计算的 newState 放在 updateQueue.memoriedState 上，表示本次渲染后当前 Fiber(workInProgress) 节点的状态是 newState
 * 5. 如果没有跳过的更新，那么 updateQueue.baseState 也是newState，因为本次渲染所有更新都已经被消费，当前 workInProgress 后面的更新，应该以本次更新计算的状态进行更新
 * 6. 如果存在跳过的更新，那么 updateQueue.baseState 存放的是第一个没有跳过的更新跟最初的 baseState 计算得到的 state（如果第一个更新就被跳过那么 updateQueue.baseState 就是 workInProgress 最初的baseState）
 * @param {*} workInProgress
 * @param {*} props
 * @param {*} renderLanes
 */
function processUpdateQueue(workInProgress, props, renderLanes) {
  const queue = workInProgress.updateQueue;
  let firstBaseUpdate = queue.firstBaseUpdate;
  let lastBaseUpdate = queue.lastBaseUpdate;
  let pendingQueue = queue.shared.pending;
  /**
   * 解开 queue.shared.pending 的环状结构
   * 并用 firstBaseUpdate 跟 lastBaseUpdate 指向更新队列的头跟尾
   */
  if (pendingQueue !== null) {
    queue.shared.pending = null;
    // 解开环
    const lastPendingUpdate = pendingQueue;
    const firstPendingUpdate = lastPendingUpdate.next;
    lastPendingUpdate.next = null;
    // 将 pending 添加到 lastBaseUpdate 后
    if (lastBaseUpdate === null) {
      firstBaseUpdate = firstPendingUpdate;
    } else {
      lastBaseUpdate.next = firstPendingUpdate;
    }

    lastBaseUpdate = lastPendingUpdate;
    // 存在更新
    if (firstBaseUpdate !== null) {
      let newState = queue.baseState;
      let newBaseState = null;
      // 记录跳的更新的起始结点
      let newFirstBaseUpdate = null;
      // 记录跳的更新的结束结点
      let newLastBaseUpdate = null;
      let update = firstBaseUpdate;
      do {
        const updateLane = update.lane;
        // 如果有需要跳过的更新
        if (!isSubsetOfLanes(renderLanes, updateLane)) {
          const clone = {
            lane: updateLane,
            tag: update.tag,
            payload: update.payload,
            next: null,
          };

          if (newLastBaseUpdate === null) {
            newFirstBaseUpdate = newLastBaseUpdate = clone;
            newBaseState = newState; // 用 newBaseState 记录第一个需要跳过更新时的状态
          } else {
            // 将跳过的更新加入到 newLastBaseUpdate 后面
            newLastBaseUpdate = newLastBaseUpdate.next = clone;
          }
        } else {
          // 这个更新的优先级满足渲染条件，不需要跳过
          if (newLastBaseUpdate !== null) {
            // 如果已经存在了跳过的更新，那么满足条件的更新也需要加入到跳过更新的列表后面（在执行执行跳过的更新时，需要依赖此次更新计算状态）
            const clone = {
              lane: NoLane, // 标记为NoLane永远不能被跳过
              tag: update.tag,
              payload: update.payload,
              next: null,
            };
            newLastBaseUpdate = newLastBaseUpdate.next = clone;
          }
          // 计算此时更新的状态
          newState = getStateFromUpdate(update, newState, props, null);
        }
        // 指向下一个更新
        update = update.next;
      } while (update);
      // 如果没有跳过的更新，那么通过 updateQueue 中所有 update计算的 newState 就是 newBaseState
      // 如果存在跳过的更新，那么 newBaseState 是第一个跳过的更新前的 update 计算的 newState，后面在执行跳过的更新时，会从此状态作为基础状态进行计算
      if (newLastBaseUpdate === null) {
        newBaseState = newState;
      }

      queue.baseState = newBaseState;
      // 将跳过的更新添加继续添加queue中
      queue.firstBaseUpdate = newFirstBaseUpdate;
      queue.lastBaseUpdate = newLastBaseUpdate;
      workInProgress.memoizedState = newState; // 将此次更新的状态
    }
  }
}

// let fiber = { memoizedState: { id: 1 } };
// initializeUpdateQueue(fiber);

// let update1 = createUpdate(SyncLane);
// update1.payload = {
//   name: 'react',
// };

// enqueueUpdate(fiber, update1);

// let update2 = createUpdate(DefaultLane);
// update2.payload = { age: 14 };
// enqueueUpdate(fiber, update2);
// processUpdateQueue(fiber, null, SyncLane);

// let update3 = createUpdate(DefaultLane);
// update3.payload = { address: '地球' };
// enqueueUpdate(fiber, update3);
// processUpdateQueue(fiber, null, DefaultLane);

// console.log(fiber);

let fiber = { memoizedState: { text: '' } };
initializeUpdateQueue(fiber);

const A = createUpdate(4);
A.payload = function (prevState) {
  return {
    text: prevState.text + 'A',
  };
};

enqueueUpdate(fiber, A);

const B = createUpdate(1);
B.payload = function (prevState) {
  return {
    text: prevState.text + 'B',
  };
};

enqueueUpdate(fiber, B);

processUpdateQueue(fiber, null, 1);
console.log(fiber);

const C = createUpdate(2);
C.payload = function (prevState) {
  return {
    text: prevState.text + 'C',
  };
};

enqueueUpdate(fiber, C);

processUpdateQueue(fiber, null, 2);
console.log(fiber);

const D = createUpdate(8);
D.payload = function (prevState) {
  return {
    text: prevState.text + 'D',
  };
};

enqueueUpdate(fiber, D);

processUpdateQueue(fiber, null, 8);
console.log(fiber);

const E = createUpdate(4);
E.payload = function (prevState) {
  return {
    text: prevState.text + 'E',
  };
};

enqueueUpdate(fiber, E);

processUpdateQueue(fiber, null, 4);
console.log(fiber);

const F = createUpdate(2);
F.payload = function (prevState) {
  return {
    text: prevState.text + 'F',
  };
};

enqueueUpdate(fiber, F);

processUpdateQueue(fiber, null, 2);
console.log(fiber);

const G = createUpdate(1);
G.payload = function (prevState) {
  return {
    text: prevState.text + 'G',
  };
};

enqueueUpdate(fiber, G);

const H = createUpdate(4);
H.payload = function (prevState) {
  return {
    text: prevState.text + 'H',
  };
};

enqueueUpdate(fiber, H);
